/**
 * 
 */
package ru.olympus.antonyhands.ao.client.widgets;

import java.util.ArrayList;
import java.util.List;

import ru.olympus.antonyhands.ao.shared.util.StringPair;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;

/**
 * Таблица в виде дерева
 * 
 * @author AntonyHands
 * @since 05.03.2012
 */
public class TreeTable extends FlexTable {

	private TreeTableDataSource _ds;
	
	public void setDataSource(TreeTableDataSource ds)
	{
		_ds = ds;
		repaint();
	}

	public void repaint()
	{
		setBorderWidth(1);
		removeAllRows();
		if (_ds == null)
			return;
		setRow(0, false, _ds.getHeaderRow());
		for (int i = 0; i < _ds.listRows().size(); i++)
			setRowHierarchical(getRowCount(), false, _ds.listRows().get(i));
	}

	private void setRow(int index, boolean insert, TreeTableDataSourceRow rowData)
	{
		if (insert)
			insertRow(index);
		if (rowData.hasChildren())
		{
			FoldUnfoldButton button = new FoldUnfoldButton(rowData, this);
			setWidget(index, 0, button);
		}
//		setWidget(index, 0, new Label("0"));
		for (int i = 0; i < rowData.getColumnCount(); i++)
			setHTML(index, i + 1, "<div style=\"" + rowData.getCellStyle(i) + "\">" + rowData.getCellValue(i) + "</div>");
	}

	private void setChildRows(boolean insert, int parentIndex, TreeTableDataSourceRow rowData)
	{
		if (rowData.hasChildren() && rowData.isOpened())
		{
			int index = parentIndex + 1;
			for (int i=0; i<rowData.listChildRows().size(); i++)
			{
				TreeTableDataSourceRow child = rowData.listChildRows().get(i);
				setRowHierarchical(index, insert, child);
				index += child.getRowsNumber();
			}
		}
	}

	private void setRowHierarchical(int index, boolean insert, TreeTableDataSourceRow rowData)
	{
		setRow(index, insert, rowData);
		setChildRows(insert, index, rowData);
	}

	/**
	 * Источник данных для "деревянной" таблицы
	 * 
	 * @author AntonyHands
	 * @since 05.03.2012
	 */
	public static class TreeTableDataSource implements IsSerializable {
		
		private TreeTableDataSourceRow headRow;
		private List<TreeTableDataSourceRow> rows;

		public int getColumnCount()
		{
			return headRow.getColumnCount();
		}
		
		public TreeTableDataSourceRow getHeaderRow()
		{
			return headRow;
		}

		public List<TreeTableDataSourceRow> listRows()
		{
			return rows;
		}

		public void setHeadRow(TreeTableDataSourceRow headRow) {
			this.headRow = headRow;
		}

		public void setRows(List<TreeTableDataSourceRow> rows) {
			this.rows = rows;
		}

		public void addRow(TreeTableDataSourceRow row)
		{
			if (rows == null)
				rows = new ArrayList<TreeTableDataSourceRow>();
			rows.add(row);
		}
	}

	public static class TreeTableDataSourceRow implements IsSerializable {

		private List<TreeTableDataSourceRow> childRows;
		private boolean opened;
		private List<StringPair> cells;
		
		public boolean hasChildren()
		{
			return (childRows != null) && childRows.size() > 0;
		}
		
		public boolean isOpened()
		{
			return opened;
		}
		
		public void setOpened(boolean _opened)
		{
			opened = _opened;
		}

		public int getColumnCount()
		{
			return cells.size();
		}
		
		public List<TreeTableDataSourceRow> listChildRows()
		{
			return childRows;
		}
		
		public String getCellValue(int index)
		{
			return cells.get(index).getKey();
		}
		
		public String getCellStyle(int index)
		{
			return cells.get(index).getValue();
		}

		public void setChildRows(List<TreeTableDataSourceRow> childRows) {
			this.childRows = childRows;
		}

		public void setCells(List<StringPair> cells) {
			this.cells = cells;
		}

		public int getRowsNumber()
		{
			int res = 1;
			if (hasChildren() && isOpened())
				for (TreeTableDataSourceRow child : childRows)
					res += child.getRowsNumber();
			return res;
		}
	}

	private class FoldUnfoldButton extends Button
    {
    	/**
    	 * true - значок "развернуть"
    	 */
    	private TreeTableDataSourceRow _row;
    	private TreeTable _table;

    	public FoldUnfoldButton(TreeTableDataSourceRow row, TreeTable table)
    	{
    		_row = row;
    		_table = table;
    		updateView();

    		final FoldUnfoldButton _this = this;

    		addClickHandler(new ClickHandler() {
				@Override
				public void onClick(ClickEvent event) {
					int index = -1;
					for (int i = 0; i < _table.getRowCount(); i++)
					{
						Object o = _table.getWidget(i, 0);
						if ((o != null) && _this.equals(o))
						{
							index = i;
							break;
						}
					}
					if (index >= 0)
						if (_row.isOpened())
						{
							for (int i = 1; i < _row.getRowsNumber(); i++)
							{
								_table.removeRow(index + 1);
							}
							_row.setOpened(false);
						}
						else
						{
							_row.setOpened(true);
							setChildRows(true, index, _row);
						}
					updateView();
				}
			});
    	}

    	private void updateView()
    	{
    		if (_row.isOpened())
    			setText("-");
    		else
    			setText("+");
    	}
    }
}
